package com.zjut.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zjut.dao.PaperQuestionDao;
import com.zjut.domain.*;
import com.zjut.service.*;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.zjut.controller.Code.*;

@RestController
@RequestMapping("/paper")
public class PaperController {
    @Autowired
    private PaperService paperService;
    @Autowired
    private ModelService modelService;
    @Autowired
    private QuestionsService questionsService;
    @Autowired
    private PaperQuestionService paperQuestionService;
    @Autowired
    private ChapterService chapterService;

    //添加试卷
    @PostMapping
    public Result save(@RequestBody Paper paper) {
        boolean flag = paperService.save(paper);
        return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);
    }

    //修改试卷
    @PutMapping
    public Result update(@RequestBody Paper paper) {
        boolean flag = paperService.save(paper);
        return new Result(flag ? Code.UPDATE_OK : Code.SAVE_ERR, flag);
    }

    //删除试卷
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        boolean flag1 = paperService.delete(id);
        boolean flag2 = paperQuestionService.deleteByPaperId(id);
        return new Result((flag1 && flag2) ? Code.DELETE_OK : Code.DELETE_ERR, (flag1 && flag2));
    }

    @GetMapping("/ques/{paperId}")
    public Result getQuestions(@PathVariable int paperId) {
        List<FinalQuestions> questionsList = new ArrayList<>();
        List<Integer> idList = paperQuestionService.getQuestionIdsByPaperId(paperId);
        Paper paper = paperService.getById(paperId);
        Model model = modelService.getById(paper.getModelId());

        List<Questions> questions = new ArrayList<>();
        for (int i = 0; i < idList.size(); i++) {
            Integer id = idList.get(i);
            Questions question = questionsService.getById(id);
            FinalQuestions finalQuestion = new FinalQuestions();
            finalQuestion.setQuestion(question.getQuestion());
            finalQuestion.setAnswer(question.getAnswer());
            finalQuestion.setType(question.getType());
            finalQuestion.setId(question.getId());
            finalQuestion.setDifficulty(question.getDifficulty());
            finalQuestion.setChapter(question.getChapter());
            finalQuestion.setSection(question.getSection());
            finalQuestion.setKnowledge(chapterService.getKnowledge(question.getChapter(), question.getSection()));
            finalQuestion.setRequirement(chapterService.getRequirement(question.getChapter(), question.getSection()));
            finalQuestion.setScore(calculateScore(question.getType(), model));

            questionsList.add(finalQuestion);
        }
        if (questionsList.size() > 0) return new Result(GET_OK, questionsList, "读取成功");
        else return new Result(GET_ERR, null, "读取失败");
    }

    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        Paper paper = paperService.getById(id);
        Integer code = paper != null ? Code.GET_OK : Code.GET_ERR;
        String msg = paper != null ? "" : "数据查询失败，请重试！";
        return new Result(code, paper, msg);
    }

    @GetMapping
    public Result getAll() {
        List<Paper> paperList = paperService.getAll();
        Integer code = paperList != null ? Code.GET_OK : Code.GET_ERR;
        String msg = paperList != null ? "" : "数据查询失败，请重试！";
        return new Result(code, paperList, msg);
    }

    @GetMapping("/{currentPage}/{pageSize}")
    public Result getPage(@PathVariable int currentPage, @PathVariable int pageSize, Paper paper) {

        IPage<Paper> paperList;
        paperList = paperService.getPage(currentPage, pageSize, paper);
        if (currentPage > paperList.getPages()) {
            paperList = paperService.getPage((int) paperList.getPages(), pageSize, paper);
        }
        Integer code = paperList != null ? Code.GET_OK : Code.GET_ERR;
        String msg = paperList != null ? "" : "数据查询失败，请重试！";
        return new Result(code, paperList, msg);
    }


    //******组卷算法******

    int count = 0;

    //组卷功能
    @PostMapping("generate")
    public Result generatePaper(@RequestBody Map<String, Object> params) {

        //接收并转换参数
        List<Map<String, Object>> chapterMapList = (List<Map<String, Object>>) params.get("chapterList");

        List<Chapter> chapterList = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (Map<String, Object> chapterMap : chapterMapList) {
            Chapter chapter = objectMapper.convertValue(chapterMap, Chapter.class);
            chapterList.add(chapter);
        }

        Map<String, Object> paperMap = (Map<String, Object>) params.get("formData");
        Paper paper = objectMapper.convertValue(paperMap, Paper.class);

        String methodStr = (String) params.get("method");
        int method = Integer.parseInt(methodStr);

        String repeatStr = (String) params.get("repeat");
        boolean r = Boolean.parseBoolean(repeatStr);
        //----
        if (paper.getDifficulty() > 0.9 || paper.getDifficulty() < 0.3) {
            return new Result(GENERATE_ERR, null, "难度系数应当在0.3-0.9之间");
        }

        //获取所选模板
        Model model = modelService.getById(paper.getModelId());
        //调用组卷算法
        List<FinalQuestions> allQuestions = new ArrayList<>();
        if (model.getJudgmentNumber() != 0)
            allQuestions.addAll(generatePaper("判断题", paper, model, chapterList,r));
        if (model.getChoiceNumber() != 0)
            allQuestions.addAll(generatePaper("选择题", paper, model, chapterList,r));
        if (model.getFillNumber() != 0)
            allQuestions.addAll(generatePaper("填空题", paper, model, chapterList,r));
        if (model.getShortAnswerNumber() != 0)
            allQuestions.addAll(generatePaper("简答题", paper, model, chapterList,r));
        if (model.getCalculationNumber() != 0)
            allQuestions.addAll(generatePaper("计算题", paper, model, chapterList,r));
        if (model.getOtherNumber() != 0)
            allQuestions.addAll(generatePaper("其它题", paper, model, chapterList,r));

        //校验试卷难度系数
        double difficulty = 0.0;

        for (FinalQuestions q : allQuestions) {
            difficulty += q.getDifficulty() * q.getScore();
        }
        difficulty /= model.getScore();
        DecimalFormat df = new DecimalFormat("#.00");//保留两位小数
        difficulty = Double.parseDouble(df.format(difficulty));

        //校验章节占比
        double[] probabilities = new double[chapterList.size()];
        double[] score = new double[chapterList.size()];
        double num = 0.0;

        for (int i = 0; i < chapterList.size(); i++) {
            probabilities[i] = chapterList.get(i).getProportion();
            num += probabilities[i];
            for (FinalQuestions q : allQuestions) {
                if (q.getKnowledge().equals(chapterList.get(i).getKnowledge())) {
                    score[i] += q.getScore();
                }
            }
        }
        for (int i = 0; i < chapterList.size(); i++) {
            probabilities[i] /= num;
            score[i] /= model.getScore();
        }

        Map<String, Object> param = new HashMap<>();
        param.put("chapterList", chapterList.stream().map(chapter -> objectMapper.convertValue(chapter, Map.class)).collect(Collectors.toList()));
        param.put("formData", objectMapper.convertValue(paper, Map.class));
        // 将method转换为字符串
        String methodStr2 = String.valueOf(method);
        // 将methodStr放入params中
        param.put("method", methodStr2);


        //组卷模式,回溯
        double diff = 0.0;
        double qwq = 0.0;
        if (method == 1) {
            diff = 1.1;
            qwq = 2.0;
        } else if (method == 2) {
            diff = 1.05;
            qwq = 1.75;
        } else if (method == 3) {
            diff = 1.15;
            qwq = 3;
        }

        for (int i = 0; i < chapterList.size(); i++) {
            if (probabilities[i] > qwq * score[i] || probabilities[i] < score[i] / qwq) {
//                         System.out.println("章节比例不对!");
                count++;
                if (count > 1999) {
                    this.count = 0;
                    System.out.println(count);
                    return new Result(GENERATE_ERR, null, "组卷超时,请检查条件");
                }
                return generatePaper(param);
            }
        }
        if ((difficulty > paper.getDifficulty() * diff) || (difficulty < paper.getDifficulty() / diff)) {
//                        System.out.println("难度系数不对!");
            count++;
            if (count > 1999) {
                this.count = 0;
                System.out.println(count);
                return new Result(GENERATE_ERR, null, "组卷超时,请检查条件");
            }
            return generatePaper(param);
        }

        System.out.println("*****" + difficulty + "*****");
        System.out.println("c" + count);
        System.out.println("组卷模式:" + method);
        String msg = "组卷成功,共抽取" + this.count + "次";
        this.count = 0;
        return new Result(GENERATE_OK, allQuestions, msg);
    }

    //组卷算法
    public List<FinalQuestions> generatePaper(String type, Paper paper, Model model, List<Chapter> chapterList ,Boolean r) {

        //注入章节范围、题型，初步筛选
        List<FinalQuestions> questionsList = questionsService.selectQuestions(type, paper);

        //计算单个题目分数
        for (FinalQuestions q : questionsList) {
            q.setScore(calculateScore(type, model));
        }

        //将题目列表随机打乱后进行升序排序
        Collections.shuffle(questionsList);
        Collections.sort(questionsList);

        //注入章节权重
        double[] probabilities = new double[chapterList.size()];
        String[] knowledges = new String[chapterList.size()];

        for (int i = 0; i < chapterList.size(); i++) {
            probabilities[i] = chapterList.get(i).getProportion();
            knowledges[i] = chapterList.get(i).getKnowledge();
        }
        //根据试卷整体难度系数和标准差,作不同难度系数所对应的正态分布的概率模型
        NormalDistribution normalDistribution = new NormalDistribution(paper.getDifficulty(), 0.3);
        double[][] probability = new double[100][chapterList.size()];
        double sum = 0.0;
        for (int i = 0; i < 100; i++) {
            for (int j = 0; j < chapterList.size(); j++) {
                probability[i][j] = normalDistribution.density(i / 100.0) * probabilities[j];
                sum += probability[i][j];
            }
        }
        double num = 0.0;
        for (int i = 0; i < 100; i++) {
            for (int j = 0; j < chapterList.size(); j++) {
                probability[i][j] = probability[i][j] / sum;
                num += probability[i][j];
            }
        }
        //System.out.println("num:"+num);
        // 使用随机数确定哪些题目被选中
        int allNumber = calculateNumber(type, model);
        int repeat = 0;
        Random random = new Random();
        List<FinalQuestions> selectedQuestions = new ArrayList<>();
        while (selectedQuestions.size() < allNumber) {
            double randNum = random.nextDouble();//0~1随机数
            double cumProb = 0;
            double diff = 0;
            String kn;
            boolean foundQuestion = false; // 添加一个标记，用于记录是否找到了符合条件的题目
            outerLoop:
            for (int i = 0; i < 100; i++) {
                for (int j = 0; j < chapterList.size(); j++) {
                    cumProb += probability[i][j];
                    if (randNum <= cumProb) {
                        cumProb = 0;
                        diff = i / 100.0;
                        kn = knowledges[j];
                        //若找到符合难度值问题，跳出循环
                        for (FinalQuestions q : questionsList) {
                            if (q.getDifficulty() == diff && q.getKnowledge().equals(kn)) {
                                //判断题目是否被选
                                if (selectedQuestions.contains(q)) {
                                    continue;
                                }
                                if(r){
                                    //近三年题目<30%
                                    if (q.getYear() > Calendar.getInstance().get(Calendar.YEAR) - 3) {
                                        if (repeat > 0.3f * allNumber) {
                                            continue;
                                        } else {
                                            repeat++;
                                        }
                                    }
                                }
                                selectedQuestions.add(q);
                                // System.out.println(q.getYear());
                                foundQuestion = true; // 找到符合条件的题目，设置标记为 true
                                break;
                            }
                        }
                        break;
                    }
                }
                if (foundQuestion) { // 检查标记的值，如果为 true，则使用 break 结合标签跳出外层循环
                    break outerLoop;
                }
            }
        }
        //将选好题目从易到难排序
        Collections.sort(selectedQuestions, Collections.reverseOrder());
        return selectedQuestions;
    }

    //计算题目分值
    private Double calculateScore(String type, Model model) {
        Double score = 0.0;
        switch (type) {
            case "选择题":
                score = (double) (model.getChoiceScore() / model.getChoiceNumber());
                break;
            case "填空题":
                score = (double) (model.getFillScore() / model.getFillNumber());
                break;
            case "判断题":
                score = (double) (model.getJudgmentScore() / model.getJudgmentNumber());
                break;
            case "简答题":
                score = (double) (model.getShortAnswerScore() / model.getShortAnswerNumber());
                break;
            case "计算题":
                score = (double) (model.getCalculationScore() / model.getCalculationNumber());
                break;
            default:
                score = (double) (model.getOtherScore() / model.getOtherNumber());
        }
        return score;
    }

    //计算题目数量
    private Integer calculateNumber(String type, Model model) {
        int num = 0;
        switch (type) {
            case "选择题":
                num = model.getChoiceNumber();
                break;
            case "填空题":
                num = model.getFillNumber();
                break;
            case "判断题":
                num = model.getJudgmentNumber();
                break;
            case "简答题":
                num = model.getShortAnswerNumber();
                break;
            case "计算题":
                num = model.getCalculationNumber();
                break;
            default:
                num = model.getOtherNumber();
        }
        return num;
    }


    //******试卷导出******

    //试卷导出
    @PostMapping("export")
    public Result exportPaper(@RequestBody Map<String, Object> params) throws Exception {
        //接收并转换参数
        List<Map<String, Object>> questionsMapList = (List<Map<String, Object>>) params.get("dataList");

        List<FinalQuestions> questionsList = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (Map<String, Object> questionMap : questionsMapList) {
            FinalQuestions question = objectMapper.convertValue(questionMap, FinalQuestions.class);
            questionsList.add(question);
        }
        Map<String, Object> paperMap = (Map<String, Object>) params.get("formData");
        Paper paper = objectMapper.convertValue(paperMap, Paper.class);

        //检测试卷题型
        Boolean[] questionType = new Boolean[6];
        for (FinalQuestions q : questionsList) {
            switch (q.getType()) {
                case "判断题":
                    questionType[0] = true;
                    break;
                case "选择题":
                    questionType[1] = true;
                    break;
                case "填空题":
                    questionType[2] = true;
                    break;
                case "简答题":
                    questionType[3] = true;
                    break;
                case "计算题":
                    questionType[4] = true;
                    break;
                case "其它题":
                    questionType[5] = true;
                    break;
            }
        }
        Boolean[] answerType = new Boolean[5];
        for (int i = 0; i < 5; i++) {
            answerType[i] = questionType[i];
        }

        exportQuestion(paper, questionsList, questionType);
        exportAnswer(paper, questionsList, answerType);

        return new Result(EXPORT_OK, null, "导出成功");
    }

    //导出试题
    public void exportQuestion(Paper paper, List<FinalQuestions> questionsList, Boolean[] questionType) throws Exception {

        Model model = modelService.getById(paper.getModelId());
        // 初始化一个 XWPFDocument 对象，代表一个空的 Word 文档
        XWPFDocument document = new XWPFDocument();

        //输出试卷标题
        XWPFParagraph titleParagraph = document.createParagraph();
        titleParagraph.setAlignment(ParagraphAlignment.CENTER); //居中对齐
        XWPFRun titleRun = titleParagraph.createRun();
        titleRun.setText(paper.getName());
        titleRun.setBold(true); // 加粗
        titleRun.setFontSize(22);

        //处理试卷题型和分值
        char[] typeNum = {'一', '二', '三', '四', '五', '六'};
        int k = 0;

        //遍历所有题目
        for (int i = 0; i < questionsList.size(); i++) {
            FinalQuestions question = questionsList.get(i);
            XWPFParagraph paragraph = document.createParagraph();

            // 设置行距
            CTPPr ctPPr = paragraph.getCTP().getPPr();
            if (ctPPr == null) {
                ctPPr = paragraph.getCTP().addNewPPr();
            }
            CTSpacing spacing = ctPPr.isSetSpacing() ? ctPPr.getSpacing() : ctPPr.addNewSpacing();
            spacing.setLineRule(STLineSpacingRule.EXACT);
            spacing.setLine(BigInteger.valueOf(400));

            XWPFRun typeRun = paragraph.createRun();
            typeRun.setBold(true); // 加粗
            typeRun.setFontFamily("SimHei"); // 将字体设置为黑体
            typeRun.setFontSize(12); // 字号为小四

            XWPFRun questionRun = paragraph.createRun();
            questionRun.setFontFamily("宋体");
            questionRun.setFontSize(11);
            //判断题*
            if ("判断题".equals(question.getType())) {
                //设置题目类型
                if (questionType[0]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、判断题(每小题" + model.getJudgmentScore() / model.getJudgmentNumber() + "分,共" + model.getJudgmentScore() + "分,对的打“√”，错的打“×”)");
                    questionRun.addBreak();
                    questionType[0] = false;
                    k++;
                }
                // 设置题号
                questionRun.setText((i + 1) + "、");
                questionRun.setText(question.getQuestion());
            }

            //选择题**
            if ("选择题".equals(question.getType())) {
                //设置题目类型
                if (questionType[1]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、选择题(每小题" + model.getChoiceScore() / model.getChoiceNumber() + "分,共" + model.getChoiceScore() + "分)");
                    questionRun.addBreak();
                    questionType[1] = false;
                    k++;
                }

                // 设置题号
                questionRun.setText((i + 1) + "、");
                questionRun.setText(question.getQuestion().replaceAll("[A-D]\\..*", ""));
                questionRun.addBreak();
                // 获取所有的选项
                String regexA = "A\\..*?(?=B\\.)";
                String regexB = "B\\..*?(?=C\\.)";
                String regexC = "C\\..*?(?=D\\.)";
                String regexD = "D\\..*";
                Matcher matcherA = Pattern.compile(regexA).matcher(question.getQuestion());
                Matcher matcherB = Pattern.compile(regexB).matcher(question.getQuestion());
                Matcher matcherC = Pattern.compile(regexC).matcher(question.getQuestion());
                Matcher matcherD = Pattern.compile(regexD).matcher(question.getQuestion());
                List<String> options = new ArrayList<>();
                while (matcherA.find()) {
                    options.add(matcherA.group());
                }
                while (matcherB.find()) {
                    options.add(matcherB.group());
                }
                while (matcherC.find()) {
                    options.add(matcherC.group());
                }
                while (matcherD.find()) {
                    options.add(matcherD.group());
                }

                int[] totalLength = new int[4];
                for (int j = 0; j < 4; j++)   // 获取需要统计的字符串
                {
                    char[] charArray = options.get(j).toCharArray();  // 将字符串转换成字符数组
                    int chineseCount = 0;  // 中文字符数量
                    int englishCount = 0;  // 英文字符数量

                    for (char c : charArray) {
                        //  if (Character.isLetter(c)|| Character.isDigit(c))
                        if (String.valueOf(c).matches("[\u4e00-\u9fa5]")) {  // 如果是中文字符
                            chineseCount++;
                        } else {
                            englishCount++;
                        }
                    }
                    totalLength[j] = chineseCount * 2 + englishCount;  // 总长度为中文字符数乘以2再加上英文字符数
                    //   System.out.println(totalLength[j]);
                }

                //   System.out.println(options);
                //   System.out.println("options.size:" + options.size());
                // 排版题目选项
                if (totalLength[0] + totalLength[1] + totalLength[2] + totalLength[3] < 48) {
                    questionRun.addTab();
                    questionRun.setText(options.get(0));
                    questionRun.addTab();
                    questionRun.addTab();
                    questionRun.setText(options.get(1));
                    questionRun.addTab();
                    questionRun.addTab();
                    questionRun.setText(options.get(2));
                    questionRun.addTab();
                    questionRun.addTab();
                    questionRun.setText(options.get(3));
                } else if (totalLength[0] + totalLength[1] < 48 && totalLength[2] + totalLength[3] < 48) {
                    //使2*2情况下选项对齐
                    int[] tabNum = {5, 10, 14, 19, 23, 28, 32};
                    int m = 0, n = 0;
                    for (int j = 0; j < 7; j++) {
                        if (totalLength[0] < tabNum[j]) {
                            m = j;
                            break;
                        }
                    }
                    for (int j = 0; j < 7; j++) {
                        if (totalLength[2] < tabNum[j]) {
                            n = j;
                            break;
                        }
                    }

                    questionRun.addTab();
                    questionRun.setText(options.get(0));
                    if (m < n) {
                        for (int j = 0; j < n - m; j++) {
                            questionRun.addTab();
                        }
                    }
                    questionRun.addTab();
                    questionRun.addTab();
                    questionRun.setText(options.get(1));
                    questionRun.addBreak();
                    questionRun.addTab();
                    questionRun.setText(options.get(2));
                    if (m > n) {
                        for (int j = 0; j < m - n; j++) {
                            questionRun.addTab();
                        }
                    }
                    questionRun.addTab();
                    questionRun.addTab();
                    questionRun.setText(options.get(3));
                } else {
                    questionRun.addTab();
                    questionRun.setText(options.get(0));
                    questionRun.addBreak();
                    questionRun.addTab();
                    questionRun.setText(options.get(1));
                    questionRun.addBreak();
                    questionRun.addTab();
                    questionRun.setText(options.get(2));
                    questionRun.addBreak();
                    questionRun.addTab();
                    questionRun.setText(options.get(3));
                }
            }

            //填空题***
            if ("填空题".equals(question.getType())) {
                //设置题目类型
                if (questionType[2]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、填空题(每小题" + model.getFillScore() / model.getFillNumber() + "分,共" + model.getFillScore() + "分)");
                    questionRun.addBreak();
                    questionType[2] = false;
                    k++;
                }
                // 设置题号
                questionRun.setText((i + 1) + "、");
                questionRun.setText(question.getQuestion());
            }

            //简答题****
            if ("简答题".equals(question.getType())) {
                //设置题目类型
                if (questionType[3]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、简答题(每小题" + model.getShortAnswerScore() / model.getShortAnswerNumber() + "分,共" + model.getShortAnswerScore() + "分)");
                    questionRun.addBreak();
                    questionType[3] = false;
                    k++;
                }
                // 设置题号
                questionRun.setText((i + 1) + "、");
                questionRun.setText(question.getQuestion());
                questionRun.addBreak();
                questionRun.addBreak();
            }

            //计算题*****
            if ("计算题".equals(question.getType())) {
                if (questionType[4]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、计算题(每小题" + model.getCalculationScore() / model.getCalculationNumber() + "分,共" + model.getCalculationScore() + "分)");
                    questionRun.addBreak();
                    questionType[4] = false;
                    k++;
                }

                questionRun.setText((i + 1) + "、");
                questionRun.setText(question.getQuestion());
                questionRun.addBreak();
                questionRun.addBreak();
                questionRun.addBreak();

            }

            //其它题******
            if ("其它题".equals(question.getType())) {
                //设置题目类型
                if (questionType[5]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、新题型(每小题" + model.getOtherScore() / model.getOtherNumber() + "分,共" + model.getOtherScore() + "分)");
                    paragraph.createRun().addBreak();
                    questionRun.addBreak();
                    questionType[5] = false;
                    k++;
                }
                // 设置题号
                questionRun.setText((i + 1) + "、");
                questionRun.setText(question.getQuestion());
                questionRun.addBreak();
                questionRun.addBreak();
                questionRun.addBreak();
            }
        }

        // 将 Word 文档保存到本地
        int i = 1; // 文件编号
        String fileName = paper.getName().replaceAll("[/\\\\:*?\"<>|]", "_"); // 将不合法的字符替换成下划线
        File file;
        String fName = fileName;
        String filePath = "D:\\test\\";

        while (true) {
            file = new File(filePath + fName + ".docx");
            if (file.exists()) { // 如果文件已存在，则在文件名后加上编号
                fName = fileName + "(" + i++ + ")";
            } else {
                break;
            }
        }

        // 创建文件夹
        File folder = new File(filePath);
        if (!folder.exists()) {
            folder.mkdirs();
        }

        FileOutputStream out = new FileOutputStream(file);
        document.write(out);
        out.close();
    }

    //导出答案
    public void exportAnswer(Paper paper, List<FinalQuestions> questionsList, Boolean[] answerType) throws Exception {

        Model model = modelService.getById(paper.getModelId());
        XWPFDocument document = new XWPFDocument();

        //输出试卷标题
        XWPFParagraph titleParagraph = document.createParagraph();
        titleParagraph.setAlignment(ParagraphAlignment.CENTER); //居中对齐
        XWPFRun titleRun = titleParagraph.createRun();
        titleRun.setText(paper.getName() + "答案");
        titleRun.setBold(true); // 加粗
        titleRun.setFontSize(18);

        //处理试卷题型和分值
        int k = 0;
        char[] typeNum = {'一', '二', '三', '四', '五', '六'};

        XWPFTable choiceTable = null;
        XWPFTable judgmentTable = null;
        //遍历所有题目
        for (int i = 0; i < questionsList.size(); i++) {
            FinalQuestions question = questionsList.get(i);

            //判断题*
            if ("判断题".equals(question.getType())) {
                //设置题目类型
                if (answerType[0]) {
                    XWPFParagraph paragraph = document.createParagraph();

                    // 设置行距
                    CTPPr ctPPr = paragraph.getCTP().getPPr();
                    if (ctPPr == null) {
                        ctPPr = paragraph.getCTP().addNewPPr();
                    }
                    CTSpacing spacing = ctPPr.isSetSpacing() ? ctPPr.getSpacing() : ctPPr.addNewSpacing();
                    spacing.setLineRule(STLineSpacingRule.EXACT);
                    spacing.setLine(BigInteger.valueOf(400));

                    XWPFRun typeRun = paragraph.createRun();
                    typeRun.setBold(true); // 加粗
                    typeRun.setFontFamily("SimHei"); // 将字体设置为黑体
                    typeRun.setFontSize(12); // 字号为小四
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、判断题(每小题" + model.getJudgmentScore() / model.getJudgmentNumber() + "分,共" + model.getJudgmentScore() + "分,对的打“√”，错的打“×”)");
                    typeRun.addBreak();
                    answerType[0] = false;
                    k++;
                    // 生成表格
                    if (model.getJudgmentNumber() <= 10) {
                        judgmentTable = document.createTable(2, model.getJudgmentNumber());

                    } else {
                        judgmentTable = document.createTable(2 * ((model.getJudgmentNumber() - 1) / 10 + 1), 10);
                    }

                    // 设置表格样式
                    CTTblPr tblPr = judgmentTable.getCTTbl().addNewTblPr();
                    tblPr.addNewTblStyle().setVal("TableGrid");
                    // 获取表格所有行
                    List<XWPFTableRow> rows = judgmentTable.getRows();
                    // 设置列宽和行高
                    for (XWPFTableRow row : rows) {
                        List<XWPFTableCell> cells = row.getTableCells();
                        for (XWPFTableCell cell : cells) {
                            CTTcPr tcpr = cell.getCTTc().addNewTcPr();
                            CTTblWidth width = tcpr.addNewTcW();
                            width.setW(BigInteger.valueOf((long) (1.4 * 1440)));
                            width.setType(STTblWidth.DXA);

                            CTTrPr trpr = row.getCtRow().addNewTrPr();
                            CTHeight ht = trpr.addNewTrHeight();
                            ht.setVal(BigInteger.valueOf((long) (0.3 * 1440)));
                        }
                    }
                }
                int m = i + 1;
                // 设置第 i 道选择题的题干
                int row = 2 * ((m - 1) / 10 + 1) - 2; // 获取题号所在的行数
                int col = (m - 1) % 10; // 获取所在的列数
                XWPFTableCell cell = judgmentTable.getRow(row).getCell(col); // 获取指定单元格
                cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                XWPFParagraph stemPara = cell.getParagraphs().get(0); // 获取单元格中的段落
                stemPara.setAlignment(ParagraphAlignment.CENTER);  // 设置对齐方式为居中
                XWPFRun stemRun = stemPara.createRun(); // 创建新的文本块
                stemRun.setText(String.valueOf(m)); // 设置题干

                XWPFTableCell cell0 = judgmentTable.getRow(row + 1).getCell(col); // 获取指定单元格
                cell0.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                XWPFParagraph optionPara = cell0.getParagraphs().get(0); // 获取单元格中的段落
                optionPara.setAlignment(ParagraphAlignment.CENTER);  // 设置对齐方式为居中
                XWPFRun optionRun = optionPara.createRun(); // 创建新的文本块
                optionRun.setText(question.getAnswer()); // 设置选项
            }


            //选择题**
            if ("选择题".equals(question.getType())) {
                //设置题目类型
                if (answerType[1]) {
                    XWPFParagraph paragraph = document.createParagraph();

                    // 设置行距
                    CTPPr ctPPr = paragraph.getCTP().getPPr();
                    if (ctPPr == null) {
                        ctPPr = paragraph.getCTP().addNewPPr();
                    }
                    CTSpacing spacing = ctPPr.isSetSpacing() ? ctPPr.getSpacing() : ctPPr.addNewSpacing();
                    spacing.setLineRule(STLineSpacingRule.EXACT);
                    spacing.setLine(BigInteger.valueOf(400));

                    XWPFRun typeRun = paragraph.createRun();
                    typeRun.setBold(true); // 加粗
                    typeRun.setFontFamily("SimHei"); // 将字体设置为黑体
                    typeRun.setFontSize(12); // 字号为小四
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、选择题(每小题" + model.getChoiceScore() / model.getChoiceNumber() + "分,共" + model.getChoiceScore() + "分)");
                    typeRun.addBreak();
                    answerType[1] = false;
                    k++;
                    // 生成表格
                    choiceTable = document.createTable(2 * ((model.getChoiceNumber() - 1) / 10 + 1), 10);
                    // 设置表格样式
                    CTTblPr tblPr = choiceTable.getCTTbl().addNewTblPr();
                    tblPr.addNewTblStyle().setVal("TableGrid");
                    // 获取表格所有行
                    List<XWPFTableRow> rows = choiceTable.getRows();
                    // 设置列宽和行高
                    for (XWPFTableRow row : rows) {
                        List<XWPFTableCell> cells = row.getTableCells();
                        for (XWPFTableCell cell : cells) {
                            CTTcPr tcpr = cell.getCTTc().addNewTcPr();
                            CTTblWidth width = tcpr.addNewTcW();
                            width.setW(BigInteger.valueOf((long) (1.4 * 1440)));
                            width.setType(STTblWidth.DXA);

                            CTTrPr trpr = row.getCtRow().addNewTrPr();
                            CTHeight ht = trpr.addNewTrHeight();
                            ht.setVal(BigInteger.valueOf((long) (0.3 * 1440)));
                        }
                    }
                }
                int m = i + 1 - model.getJudgmentNumber();
                // 设置第 i 道选择题的题干
                int row = 2 * ((m - 1) / 10 + 1) - 2; // 获取题号所在的行数
                int col = (m - 1) % 10; // 获取所在的列数
                XWPFTableCell cell = choiceTable.getRow(row).getCell(col); // 获取指定单元格
                cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                XWPFParagraph stemPara = cell.getParagraphs().get(0); // 获取单元格中的段落
                stemPara.setAlignment(ParagraphAlignment.CENTER);  // 设置对齐方式为居中
                XWPFRun stemRun = stemPara.createRun(); // 创建新的文本块
                stemRun.setText(String.valueOf(i)); // 设置题号

                XWPFTableCell cell0 = choiceTable.getRow(row + 1).getCell(col); // 获取指定单元格
                cell0.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                XWPFParagraph optionPara = cell0.getParagraphs().get(0); // 获取单元格中的段落
                optionPara.setAlignment(ParagraphAlignment.CENTER);  // 设置对齐方式为居中
                XWPFRun optionRun = optionPara.createRun(); // 创建新的文本块
                optionRun.setText(question.getAnswer()); // 设置选项
//                System.out.println(i + "---");
            }

            //填空题***
            if ("填空题".equals(question.getType())) {
                XWPFParagraph paragraph = document.createParagraph();

                // 设置行距
                CTPPr ctPPr = paragraph.getCTP().getPPr();
                if (ctPPr == null) {
                    ctPPr = paragraph.getCTP().addNewPPr();
                }
                CTSpacing spacing = ctPPr.isSetSpacing() ? ctPPr.getSpacing() : ctPPr.addNewSpacing();
                spacing.setLineRule(STLineSpacingRule.EXACT);
                spacing.setLine(BigInteger.valueOf(400));

                XWPFRun typeRun = paragraph.createRun();
                typeRun.setBold(true); // 加粗
                typeRun.setFontFamily("SimHei"); // 将字体设置为黑体
                typeRun.setFontSize(12); // 字号为小四

                XWPFRun answerRun = paragraph.createRun();
                answerRun.setFontFamily("宋体");
                answerRun.setFontSize(11);
                //设置题目类型
                if (answerType[2]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、填空题(每小题" + model.getFillScore() / model.getFillNumber() + "分,共" + model.getFillScore() + "分)");
                    typeRun.addBreak();
                    answerType[2] = false;
                    k++;
                }
                // 设置题号
                answerRun.setText((i + 1) + "、");
                answerRun.setText(question.getAnswer());
            }

            //简答题****
            if ("简答题".equals(question.getType())) {
                XWPFParagraph paragraph = document.createParagraph();

                // 设置行距
                CTPPr ctPPr = paragraph.getCTP().getPPr();
                if (ctPPr == null) {
                    ctPPr = paragraph.getCTP().addNewPPr();
                }
                CTSpacing spacing = ctPPr.isSetSpacing() ? ctPPr.getSpacing() : ctPPr.addNewSpacing();
                spacing.setLineRule(STLineSpacingRule.EXACT);
                spacing.setLine(BigInteger.valueOf(400));

                XWPFRun typeRun = paragraph.createRun();
                typeRun.setBold(true); // 加粗
                typeRun.setFontFamily("SimHei"); // 将字体设置为黑体
                typeRun.setFontSize(12); // 字号为小四

                XWPFRun answerRun = paragraph.createRun();
                answerRun.setFontFamily("宋体");
                answerRun.setFontSize(11);
                //设置题目类型
                if (answerType[3]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、简答题(每小题" + model.getShortAnswerScore() / model.getShortAnswerNumber() + "分,共" + model.getShortAnswerScore() + "分)");
                    answerRun.addBreak();
                    answerType[3] = false;
                    k++;
                }
                // 设置题号
                answerRun.setText((i + 1) + "、");
                answerRun.setText(question.getQuestion());
                answerRun.addBreak();
                answerRun.setText(question.getAnswer());
            }

            //计算题*****
            if ("计算题".equals(question.getType())) {
                XWPFParagraph paragraph = document.createParagraph();

                // 设置行距
                CTPPr ctPPr = paragraph.getCTP().getPPr();
                if (ctPPr == null) {
                    ctPPr = paragraph.getCTP().addNewPPr();
                }
                CTSpacing spacing = ctPPr.isSetSpacing() ? ctPPr.getSpacing() : ctPPr.addNewSpacing();
                spacing.setLineRule(STLineSpacingRule.EXACT);
                spacing.setLine(BigInteger.valueOf(400));

                XWPFRun typeRun = paragraph.createRun();
                typeRun.setBold(true); // 加粗
                typeRun.setFontFamily("SimHei"); // 将字体设置为黑体
                typeRun.setFontSize(12); // 字号为小四

                XWPFRun answerRun = paragraph.createRun();
                answerRun.setFontFamily("宋体");
                answerRun.setFontSize(11);
                if (answerType[4]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、计算题(每小题" + model.getCalculationScore() / model.getCalculationNumber() + "分,共" + model.getCalculationScore() + "分)");
                    answerRun.addBreak();
                    answerType[4] = false;
                    k++;
                }
                answerRun.setText((i + 1) + "、");
                answerRun.setText(question.getQuestion());
                answerRun.addBreak();
                answerRun.setText(question.getAnswer());
            }

            //其它题******
            if ("其它题".equals(question.getType())) {
                XWPFParagraph paragraph = document.createParagraph();

                // 设置行距
                CTPPr ctPPr = paragraph.getCTP().getPPr();
                if (ctPPr == null) {
                    ctPPr = paragraph.getCTP().addNewPPr();
                }
                CTSpacing spacing = ctPPr.isSetSpacing() ? ctPPr.getSpacing() : ctPPr.addNewSpacing();
                spacing.setLineRule(STLineSpacingRule.EXACT);
                spacing.setLine(BigInteger.valueOf(400));

                XWPFRun typeRun = paragraph.createRun();
                typeRun.setBold(true); // 加粗
                typeRun.setFontFamily("SimHei"); // 将字体设置为黑体
                typeRun.setFontSize(12); // 字号为小四

                XWPFRun answerRun = paragraph.createRun();
                answerRun.setFontFamily("宋体");
                answerRun.setFontSize(11);
                //设置题目类型
                if (answerType[5]) {
                    typeRun.addBreak();
                    typeRun.setText(typeNum[k] + "、新题型(每小题" + model.getOtherScore() / model.getOtherNumber() + "分,共" + model.getOtherScore() + "分)");
                    paragraph.createRun().addBreak();
                    answerRun.addBreak();
                    answerType[5] = false;
                    k++;
                }
                // 设置题号
                answerRun.setText((i + 1) + "、");
                answerRun.setText(question.getQuestion());
                answerRun.addBreak();
                answerRun.setText(question.getAnswer());
            }
        }

        // 将 Word 文档保存到本地
        int i = 1; // 文件编号
        String fileName = paper.getName().replaceAll("[/\\\\:*?\"<>|]", "_") + "答案"; // 将不合法的字符替换成下划线
        File file;
        String fName = fileName;
        String filePath = "D:\\test\\";

        while (true) {
            file = new File(filePath + fName + ".docx");
            if (file.exists()) { // 如果文件已存在，则在文件名后加上编号
                fName = fileName + "(" + i++ + ")";
            } else {
                break;
            }
        }

        // 创建文件夹
        File folder = new File(filePath);
        if (!folder.exists()) {
            folder.mkdirs();
        }

        FileOutputStream out = new FileOutputStream(file);
        document.write(out);
        out.close();
    }

    //******试卷保存******

    //保存至tb_paper
    @PostMapping("save")
    public Result savePaper(@RequestBody Paper paper) {
        int id = paperService.savePaper(paper);
        return new Result(SAVE_OK, id);
    }

    //保存至tb_paper_question
    @PostMapping("saveAll")
    public Result savePaper(@RequestBody Integer[] idList) {
        Boolean flag = false;
        for (int i = 1; i < idList.length; i++) {
            PaperQuestion paperQuestion = new PaperQuestion(idList[i], idList[0]);
            //更新试题年份
            Questions question = questionsService.getById(idList[i]);
            question.setYear(Calendar.getInstance().get(Calendar.YEAR));
            questionsService.update(question);
            //
            flag = paperQuestionService.save(paperQuestion);
            if (!flag) break;
        }
        return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);
    }


    //******查看详情*******

    //查看详情
    @PostMapping("details")
    public Result details(@RequestBody Map<String, Object> params) {
        //接收并转换参数
        List<Map<String, Object>> questionsMapList = (List<Map<String, Object>>) params.get("dataList");
        List<FinalQuestions> questionsList = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (Map<String, Object> questionMap : questionsMapList) {
            FinalQuestions question = objectMapper.convertValue(questionMap, FinalQuestions.class);
            questionsList.add(question);
        }
        Map<String, Object> paperMap = (Map<String, Object>) params.get("formData");
        Paper paper = objectMapper.convertValue(paperMap, Paper.class);

        Map<String, Object> result = new HashMap<>();
        //章节列表
        List<Chapter> chapterList = chapterService.getChapter(paper);
        DecimalFormat df = new DecimalFormat("#.00");//保留两位小数
        double difficulty = 0.0, score = 0.0;

        for (FinalQuestions q : questionsList) {
            difficulty += q.getDifficulty() * q.getScore();
            score += q.getScore();
        }
        result.put("difficulty", Double.parseDouble(df.format(difficulty / score)));
        result.put("totalScore", Double.parseDouble(df.format(score)));

        for (Chapter chapter : chapterList) {
            // 遍历章节列表
            double totalScore = 0.0;
            for (FinalQuestions question : questionsList) {
                // 遍历试题列表，如果该试题属于当前章节，总分累加
                if (chapter.getKnowledge().equals(question.getKnowledge())) {
                    totalScore += question.getScore();
                }
            }
            result.put(chapter.getKnowledge(), Double.parseDouble(df.format(totalScore)));
        }
        return new Result(GET_OK, result);
    }

    @PostMapping("difficulty")
    public double getDifficulty(List<FinalQuestions> questionsList) {
        double difficulty = 0.0;
        for (FinalQuestions q : questionsList) {
            difficulty += q.getDifficulty() * q.getScore();
        }
        DecimalFormat df = new DecimalFormat("#.00");//保留两位小数
        difficulty = Double.parseDouble(df.format(difficulty));
        return difficulty;
    }

}